package com.jl.valid.annotate.aspet;

import com.jl.JLReflect;
import com.jl.JLSet;
import com.jl.JLTuple;
import com.jl.valid.annotate.Check;
import com.jl.valid.error.JLCheckError;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@Aspect
@Component
public class CheckAspet {

    /**
     * 拦截形参加了@Check注解的方法
     */
    @Pointcut("execution(* *(.., @com.jl.valid.annotate.Check (*), ..))")
    public void check() {
    }

    @Before("check()")
    public void aspet(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //参数名和参数值
        String[] parameterNames = signature.getParameterNames();
        Object[] parametersValue = joinPoint.getArgs();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Check check = parameter.getAnnotation(Check.class);
            if (check == null || !check.isValid()) {
                continue;
            }
            String name = "".equals(check.value()) ? parameterNames[i] : check.value();
            Object value = parametersValue[i];
            String message = check(name, value, check, check.groups());
            if (message != null) {
                throw new JLCheckError(message);
            }
        }
    }

    private String check(String name, Object value, Check check, Class<?>[] groups) {
        String message;
        boolean empty = check.isEmpty();
        if (value == null) {
            message = empty ? null : name + "不能为空";
        } else if (value instanceof String) {
            message = string(name, value, check);
        } else if (value instanceof Number) {
            message = number(name, value, check);
        } else if (value instanceof List) {
            message = list(name, value, check, groups);
        } else {
            //对象参数
            message = objCheck(value, check, groups);
        }
        return message;
    }

    /**
     * 字符
     */
    public String string(String name, Object value, Check check) {
        String message = null;
        long min = check.min();
        long max = check.max();
        String regex = getRegex(check.regex());
        boolean empty = check.isEmpty();
        String s = String.valueOf(value);
        if ("".equals(s.trim()) && min != 0) {
            message = empty ? null : name + "不能为空";
        }
        if (min != -1 && s.trim().length() < min) {
            message = name + "长度不能小于" + min;
        }
        if (max != -1 && s.trim().length() > max) {
            message = name + "长度不能大于" + max;
        }
        if (!"".equals(regex) && !Pattern.matches(regex, s)) {
            message = name + "格式错误";
        }
        return message;
    }

    /**
     * 数值
     */
    public String number(String name, Object value, Check check) {
        long min = check.min();
        long max = check.max();
        String regex = getRegex(check.regex());
        Number number = (Number) value;
        if (number != null) {
            if (min != -1 && number.doubleValue() < min) {
                return name + "不能小于" + min;
            }
            if (max != -1 && number.doubleValue() > max) {
                return name + "不能大于" + max;
            }
            if (!"".equals(regex) && !Pattern.matches(regex, number.toString())) {
                return name + "格式错误";
            }
        }
        return null;
    }

    /**
     * 集合
     */
    public String list(String name, Object value, Check check, Class<?>[] groups) {
        long min = check.min();
        long max = check.max();
        boolean empty = check.isEmpty();
        List list = (List) value;
        if (list.size() == 0 && min != 0) {
            return empty ? null : name + "不能为空";
        }
        if (list != null) {
            if (min != -1 && list.size() < min) {
                return name + "长度不能小于" + min;
            }
            if (max != -1 && list.size() > max) {
                return name + "长度不能大于" + max;
            }
            //对象参数
            if (list.size() > 0 && !(list.get(0) instanceof String) && !(list.get(0) instanceof Number) && !(list.get(0) instanceof Boolean)) {
                for (Object obj : list) {
                    String message = objCheck(obj, check, groups);
                    if (message != null) {
                        return message;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 对象校验
     */
    private String objCheck(Object obj, Check checks, Class<?>[] groups) {
        boolean empty = checks.isEmpty();
        if (obj == null && empty) {
            return null;
        }
        List<JLTuple.Tuple4<String, Object, Class<?>, Check>> property = new ArrayList<>();
        Check annotate = JLReflect.ClassReflect.getAnnotate(obj, Check.class);
        if (annotate != null) {
            List<JLTuple.Tuple3<String, Object, Class<?>>> allPropertys = JLReflect.PropertyReflect.getProperty(obj);
            List<JLTuple.Tuple4<String, Object, Class<?>, Check>> checkPropertys = JLReflect.PropertyReflect.getProperty(obj, Check.class);
            for (JLTuple.Tuple3<String, Object, Class<?>> tuple3 : allPropertys) {
                Check check = annotate;
                for (JLTuple.Tuple4<String, Object, Class<?>, Check> checkProperty : checkPropertys) {
                    if (tuple3.getV1().equals(checkProperty.getV1())) {
                        check = checkProperty.getV4();
                    }
                }
                JLTuple.Tuple4<String, Object, Class<?>, Check> tuple4 = new JLTuple.Tuple4<>(tuple3.getV1(), tuple3.getV2(), tuple3.getV3(), check);
                property.add(tuple4);
            }
        } else {
            property = JLReflect.PropertyReflect.getProperty(obj, Check.class);
        }
        for (JLTuple.Tuple4<String, Object, Class<?>, Check> tuple4 : property) {
            Check check = tuple4.getV4();
            if (!check.isValid()) {
                continue;
            }
            String name = "".equals(check.value()) ? tuple4.getV1() : check.value();
            Object value = tuple4.getV2();
            Class<?>[] thiGroups = check.groups();
            boolean contains = false;
            if (groups.length == 0) {
                contains = true;
            } else {
                for (Class<?> thiGroup : thiGroups) {
                    List<Class<?>> classes = JLSet.array(groups).toList();
                    if (classes.contains(thiGroup)) {
                        contains = true;
                        break;
                    }
                }
            }
            if (contains) {
                String message = check(name, value, check, groups);
                if (message != null) {
                    return message;
                }
            }
        }
        return null;
    }


    private String getRegex(String regex) {
        String result = regex;
        if ("".equals(regex)) {
            return regex;
        }
        String begin = regex.substring(0, 1);
        String end = regex.substring(regex.length() - 1);
        if (!begin.equals("^")) {
            result = "^" + result;
        }
        if (!end.equals("$")) {
            result += "$";
        }
        return result;
    }
}
